package org.game.gobang.server.handler;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.game.result.RestResult;
import org.game.result.RestResultBuilder;
import org.game.result.ResultCode;
import org.game.util.JsonUtil;
import org.slf4j.Logger;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Slf4j
public abstract class GobangServerHandler extends SimpleChannelInboundHandler<String> {
    private int readIdleTimes = 0;
    private static ConcurrentMap<String, ConcurrentMap<ChannelHandlerContext, String>> rooms = new ConcurrentHashMap<>();
    private static ConcurrentMap<ChannelHandlerContext, String> users = new ConcurrentHashMap<>();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String s) throws Exception {
        System.out.println("你好");
        RestResult restResult = JsonUtil.formJson(s, RestResult.class);
        if (restResult.getCode().equals(ResultCode.HEARTBEAT_BAG.getCode())) {
            ctx.channel().writeAndFlush(JsonUtil.toJson(restResult));
        } else {
            System.out.println(ctx.channel().remoteAddress() + " " + s);
            String methodName = restResult.getMsg();
            this.getClass().getDeclaredMethod(methodName);
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        IdleStateEvent event = (IdleStateEvent) evt;

        String eventType = null;
        switch (event.state()) {
            case READER_IDLE:
                eventType = "读空闲";
                readIdleTimes++; // 读空闲的计数加1
                break;
            case WRITER_IDLE:
                eventType = "写空闲";
                // 不处理
                break;
            case ALL_IDLE:
                eventType = "读写空闲";
                // 不处理
                break;
        }

//        System.out.println(ctx.channel().remoteAddress() + "超时事件：" + eventType);
//        if (readIdleTimes > 3) {
//            System.out.println(ctx.channel().remoteAddress() + " 读空闲超过3次，关闭连接");
//            RestResult restResult = new RestResultBuilder().setCode(400).setMsg("you are out").build();
//            ctx.channel().writeAndFlush(JsonUtil.toJson(restResult));
//            ctx.channel().close();
//        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("=== " + ctx.channel().remoteAddress() + " is active ===");
        users.put(ctx, "");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        RestResult restResult = JsonUtil.formJson(msg.toString(), RestResult.class);

        this.getClass().getDeclaredMethod(restResult.getMsg(), ChannelHandlerContext.class, Object.class)
                .invoke(this, ctx, restResult.getData());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info(ctx.channel() + " close");

        String roomName = getUsers().get(ctx);
        getUsers().remove(ctx);
        getRooms().get(roomName).remove(ctx);
        if (getRooms().get(roomName).size() <= 0) {
            getRooms().remove(roomName);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error(cause.getMessage());
    }

    public int getReadIdleTimes() {
        return readIdleTimes;
    }

    public void setReadIdleTimes(int readIdleTimes) {
        this.readIdleTimes = readIdleTimes;
    }

    public ConcurrentMap<String, ConcurrentMap<ChannelHandlerContext, String>> getRooms() {
        return rooms;
    }

    public void setRooms(ConcurrentMap<String, ConcurrentMap<ChannelHandlerContext, String>> rooms) {
        this.rooms = rooms;
    }

    public ConcurrentMap<ChannelHandlerContext, String> getUsers() {
        return users;
    }

    public void setUsers(ConcurrentMap<ChannelHandlerContext, String> users) {
        this.users = users;
    }

    protected abstract void test(ChannelHandlerContext ctx, Object value);
    protected abstract void heartbeat(ChannelHandlerContext ctx, Object value);
    protected abstract void createRoom(ChannelHandlerContext ctx, Object value);
    protected abstract void allRooms(ChannelHandlerContext ctx, Object value);
    protected abstract void joinRoom(ChannelHandlerContext ctx, Object value);
    protected abstract void click(ChannelHandlerContext ctx, Object value);
    protected abstract void win(ChannelHandlerContext ctx, Object value);
}
